0%
PROCESSING...
Tìm hiểu về Snowflake ID: Thuật toán tạo ID duy nhất có khả năng mở rộng trong Hệ thống Phân tán
Distributed Systems

Tìm hiểu về Snowflake ID: Thuật toán tạo ID duy nhất có khả năng mở rộng trong Hệ thống Phân tán

logo
Hoang Pham Minh
Share:

Thuật toán tạo ID duy nhất có khả năng mở rộng trong Hệ thống Phân tán

Hạn chế lớn nhất của UUID v4 là tính ngẫu nhiên.

Vì UUID không được sắp xếp theo thứ tự tự nhiên:

  • Các chỉ mục cơ sở dữ liệu dễ bị phân mảnh hơn

  • Hiệu suất chèn giảm

  • Sắp xếp trở nên kém hiệu quả hơn

Snowflake ID được thiết kế đặc biệt để giải quyết những vấn đề này.

Snowflake ID là gì?

Snowflake là một thuật toán tạo ID phân tán ban đầu được Twitter phát triển.

Mục tiêu của nó rất đơn giản:

  • Tạo ID độc nhất toàn cầu

  • Hỗ trợ các hệ thống phân tán

  • Tránh các cơ sở dữ liệu tập trung

  • Bảo toàn thứ tự thời gian

  • Duy trì hiệu suất cực kỳ cao

Không giống như UUID, Snowflake ID là số nguyên 64-bit gọn nhẹ.

Mỗi node trong cơ sở hạ tầng có thể độc lập tạo ID mà không cần liên hệ với dịch vụ phối hợp trung tâm.

Điều này làm cho Snowflake có khả năng mở rộng cực cao.

Cấu trúc của Snowflake ID

Một Snowflake ID bao gồm 64 bit được chia thành nhiều phần.

1 Bit Dấu

41 Bit Dấu thời gian

10 Bit ID Máy

12 Bit Chuỗi Sequence


Thành phần

Bits

Mô tả

Bit Dấu

1

Luôn là 0 để giữ cho ID luôn dương

Dấu thời gian

41

Số mili giây đã trôi qua kể từ một epoch tùy chỉnh

ID Máy

10

Nhận dạng máy chủ/node

Chuỗi Sequence

12

Bộ đếm cho các ID được tạo trong cùng một mili giây

Dấu thời gian (Timestamp)

Dấu thời gian lưu trữ số mili giây đã trôi qua kể từ một epoch tùy chỉnh.

Với 41 bit:

2^{41} \approx 69 \text{ năm}

Điều này cho phép các hệ thống Snowflake hoạt động trong nhiều thập kỷ trước khi xảy ra tràn dấu thời gian.

Vì dấu thời gian chiếm các bit quan trọng cao nhất, Snowflake ID vẫn có thể sắp xếp tự nhiên theo thời gian tạo.

Điều này có nghĩa là:

ID cao hơn = bản ghi mới hơn

Trong các hệ thống phân tán, việc tạo mã định danh duy nhất nghe có vẻ đơn giản—cho đến khi ứng dụng của bạn mở rộng ra nhiều máy chủ, cơ sở dữ liệu, khu vực và dịch vụ.

Ở quy mô của các nền tảng như Twitter, Discord, Instagram hay TikTok, các ID được tạo tự động truyền thống từ cơ sở dữ liệu nhanh chóng trở thành nút thắt cổ chai. Các hệ thống xử lý hàng triệu yêu cầu mỗi giây cần một chiến lược tạo ID nhanh, phân tán và độc nhất toàn cầu.

Đây chính xác là vấn đề mà Twitter đã tìm cách giải quyết vào năm 2010 với Snowflake: một thuật toán tạo ID phân tán, có thể sắp xếp theo thời gian, và có hiệu suất cao.

Ngày nay, các hệ thống lấy cảm hứng từ Snowflake cung cấp sức mạnh cho nhiều kiến trúc backend hiện đại trên các nền tảng truyền thông xã hội, cơ sở hạ tầng đám mây, quy trình phân tích và microservices.

Bài viết này giải thích cách thức hoạt động nội bộ của Snowflake ID, lý do chúng trở nên phổ biến, ưu điểm, hạn chế của chúng, và những thách thức kỹ thuật đằng sau việc tạo ID phân tán.

Tại sao ID Tự động Tăng (Auto-Increment) Truyền thống Thất bại ở Quy mô lớn

Trong các ứng dụng nhỏ, ID cơ sở dữ liệu tự động tăng hoàn toàn có thể chấp nhận được.

Ví dụ:

ID

Tên người dùng

1

john

2

jane

3

jack

Cơ sở dữ liệu chỉ đơn giản là tăng ID mỗi khi một bản ghi mới được chèn vào.

Tuy nhiên, cách tiếp cận này trở nên có vấn đề trong các hệ thống phân tán.

Hãy tưởng tượng bạn đang chạy:

  • Nhiều máy chủ backend

  • Nhiều phiên bản cơ sở dữ liệu

  • Nhiều khu vực hoặc trung tâm dữ liệu

Nếu tất cả các hệ thống cố gắng tạo ID một cách độc lập, xung đột là điều không thể tránh khỏi trừ khi có sự phối hợp chặt chẽ.

Các hệ thống tự động tăng truyền thống gây ra một số vấn đề kiến trúc:

  • Nút thắt cổ chai tập trung

  • Tranh chấp ghi (Write contention)

  • Độ trễ nhân bản (Replication delays)

  • Khó khăn trong việc phân mảnh cơ sở dữ liệu (Database sharding)

  • Phức tạp trong việc đồng bộ hóa xuyên khu vực

Ngay cả việc gán các dải ID riêng biệt cho mỗi máy chủ cũng trở nên khó duy trì khi cơ sở hạ tầng mở rộng một cách linh hoạt.

Ngoài ra, ID tự động tăng gần như không chứa bất kỳ siêu dữ liệu hữu ích nào:

  • Không có thông tin dấu thời gian (timestamp)

  • Không có nhận dạng node

  • Không có khả năng truy vết phân tán

Khi các hệ thống phát triển theo chiều ngang, các kỹ sư backend thường tìm kiếm các giải pháp thay thế phân tán.

UUID: Một Lựa chọn Thay thế Phổ biến

UUID (Universally Unique Identifier - Mã định danh duy nhất toàn cầu) là một trong những giải pháp phổ biến nhất.

Ví dụ:

67DB31FB-1887-4372-A8B0-E87C092D7D11

UUID cung cấp:

  • Xác suất xung đột cực kỳ thấp

  • Tạo ID phi tập trung

  • Tính duy nhất toàn cầu

Tuy nhiên, chúng cũng đi kèm với sự đánh đổi.

Loại

Ưu điểm

Hạn chế

AUTO_INCREMENT

Đơn giản và gọn nhẹ

Nút thắt cổ chai tập trung

UUID v4

Duy nhất toàn cầu

Lớn và không thể sắp xếp được

ULID

Phân tán và có thể sắp xếp

Định dạng chuỗi dài hơn

Snowflake

Phân tán, có thể sắp xếp, gọn nhẹ

Cần đồng bộ hóa đồng hồ

ID Máy (Machine ID)

ID máy xác định máy chủ nào đã tạo ID.

Với 10 bit:

2^{10}=1024 \text{ node}

Điều này cho phép các cơ sở hạ tầng phân tán lớn độc lập tạo ID mà không bị xung đột.

Chuỗi Sequence

Bộ đếm chuỗi Sequence tăng lên khi nhiều ID được tạo trong cùng một mili giây.

Với 12 bit:

2^{12}=4096 \text{ ID/ms/node}

Kết hợp trên nhiều node, điều này cho phép hàng triệu ID được tạo ra mỗi giây.

Cách thức Hoạt động của Snowflake ID

Khi một dịch vụ cần ID mới, thuật toán thực hiện theo các bước sau:

  1. Lấy dấu thời gian hiện tại theo mili giây

  2. So sánh nó với dấu thời gian trước đó

  3. Nếu vẫn trong cùng một mili giây:

    • Tăng số chuỗi sequence

  4. Nếu chuỗi sequence vượt quá 4095:

    • Chờ đến mili giây tiếp theo

  5. Kết hợp tất cả các phần thành một số nguyên 64-bit duy nhất

Quá trình này tránh:

  • Truy vấn cơ sở dữ liệu

  • Khóa phân tán (Distributed locks)

  • Phối hợp tập trung

Do đó, việc tạo Snowflake cực kỳ nhanh chóng và có khả năng mở rộng cao.

Tại sao Snowflake ID có thể sắp xếp theo Thời gian

Một trong những tính năng mạnh mẽ nhất của Snowflake là thứ tự thời gian.

Vì dấu thời gian chiếm các bit cao nhất, ID tự nhiên được sắp xếp theo thời gian tạo.

Thuộc tính này cực kỳ hữu ích cho:

  • Hệ thống chat

  • Nguồn cấp dữ liệu xã hội (Social feeds)

  • Luồng sự kiện (Event streams)

  • Ghi nhật ký phân tán

  • Quy trình phân tích (Analytics pipelines)

  • Hàng đợi tin nhắn (Message queues)

Nhiều hệ thống có thể xác định thứ tự bản ghi chỉ bằng cách so sánh giá trị ID.

Trong một số kiến trúc, các kỹ sư thậm chí có thể trích xuất dấu thời gian trực tiếp từ ID.

Ví dụ:

(timestamp << 22) + machineId + sequence

Điều này giảm sự phụ thuộc vào các cơ chế sắp xếp riêng biệt.

Các Node và Worker Phân tán

Nhiều triển khai Snowflake tổ chức việc tạo ID thành:

  • Node

  • Worker

  • Service

Ví dụ kiến trúc:

Node

Worker

Trách nhiệm

Máy chủ API

Worker 1

ID Người dùng

Máy chủ API

Worker 2

ID Bài đăng

Dịch vụ Thông báo

Worker 1

ID Thông báo

Dịch vụ Ghi nhật ký

Worker 1

ID Sự kiện

Thiết kế này cho phép các kỹ sư nhận dạng:

  • Dịch vụ nào đã tạo ID

  • Worker nào đã tạo nó

  • Thời điểm nó được tạo

Điều này trở nên có giá trị cho việc gỡ lỗi và truy vết phân tán (distributed tracing).

Các Thách thức Thực tế trong Hệ thống Snowflake

Mặc dù Snowflake rất tao nhã, các hệ thống sản xuất vẫn phải đối mặt với các thách thức vận hành.

Lệch Đồng hồ (Clock Drift)

Snowflake phụ thuộc rất nhiều vào thời gian hệ thống.

Nếu đồng hồ máy chủ chạy lùi do:

  • Đồng bộ hóa NTP

  • Sự cố máy ảo

  • Thay đổi đồng hồ thủ công

bộ tạo ID có thể tạo ra các ID không hợp lệ hoặc trùng lặp.

Nhiều triển khai giải quyết vấn đề này bằng cách:

  • Tạm thời từ chối tạo ID

  • Chờ cho đến khi đồng hồ khôi phục

  • Sử dụng đồng hồ đơn điệu (monotonic clocks) nội bộ

Tràn Chuỗi Sequence (Sequence Overflow)

Mỗi node chỉ có thể tạo:

4096 \text{ ID mỗi mili giây}

cho mỗi worker.

Nếu lưu lượng truy cập vượt quá giới hạn này:

  • Bộ tạo ID phải chờ

  • Hoặc phân phối việc tạo ID cho các worker/node bổ sung

Ở quy mô lớn, cơ sở hạ tầng thường mở rộng theo chiều ngang để tránh tắc nghẽn.

Trùng lặp ID Máy (Duplicate Machine IDs)

Nếu hai máy chủ vô tình chia sẻ cùng một ID máy, xung đột có thể xảy ra.

Điều này đòi hỏi sự phối hợp cơ sở hạ tầng cẩn thận.

Các hệ thống lớn thường quản lý ID máy bằng cách sử dụng:

  • Kubernetes StatefulSets

  • Khám phá dịch vụ (Service discovery)

  • Hệ thống quản lý cấu hình

Số JavaScript Gặp Vấn đề về Độ chính xác

Một trong những vấn đề Snowflake bị bỏ qua nhiều nhất xuất hiện trong JavaScript.

Ví dụ:

console.log(144328692659220481)

Đầu ra:

144328692659220480

Giá trị thay đổi một cách bất ngờ.

Điều này xảy ra vì JavaScript sử dụng số dấu phẩy động độ chính xác kép IEEE-754.

JavaScript chỉ hỗ trợ an toàn các số nguyên lên đến:

2^{53}-1

Bất kỳ số nguyên nào lớn hơn có thể mất độ chính xác.

Điều này tạo ra các vấn đề lớn cho Snowflake ID vì chúng thường vượt quá phạm vi số nguyên an toàn của JavaScript.

Tại sao các Hệ thống lớn Trả về Snowflake ID dưới dạng Chuỗi

Do các giới hạn về độ chính xác, nhiều hệ thống lớn trả về Snowflake ID dưới dạng chuỗi thay vì số.

Đúng:

{

  "id": "144328692659220481"

}

Không an toàn:

{

  "id": 144328692659220481

}

Đây là lý do tại sao các API từ các hệ thống như Discord thường trả về ID dưới dạng chuỗi.

Về nội bộ, các hệ thống vẫn có thể sử dụng:

  • bigint

  • uint64

  • int64

tùy thuộc vào ngôn ngữ lập trình.

Khi cần tính toán trong JavaScript hoặc TypeScript:

const id = BigInt("144328692659220481")

Điều này bảo toàn độ chính xác hoàn toàn một cách an toàn.

Ví dụ Triển khai Snowflake đơn giản bằng Node.js

Dưới đây là một triển khai Snowflake đơn giản hóa bằng Node.js.

class Snowflake {

  constructor(workerId, datacenterId, sequence = 0n) {

    this.workerId = BigInt(workerId);

    this.datacenterId = BigInt(datacenterId);

    this.sequence = sequence;

    this.twepoch = 1288834974657n;

    this.workerIdBits = 5n;

    this.datacenterIdBits = 5n;

    this.sequenceBits = 12n;

    this.sequenceMask = -1n ^ (-1n << this.sequenceBits);

    this.workerIdShift = this.sequenceBits;

    this.datacenterIdShift = this.sequenceBits + this.workerIdBits;

    this.timestampLeftShift = this.sequenceBits + this.workerIdBits + this.datacenterIdBits;

    this.lastTimestamp = -1n;

  }

  tilNextMillis(lastTimestamp) {

    let timestamp = BigInt(Date.now());

    while (timestamp <= lastTimestamp) {

      timestamp = BigInt(Date.now());

    }

    return timestamp;

  }

  nextId() {

    let timestamp = BigInt(Date.now());

    if (timestamp < this.lastTimestamp) {

      throw new Error("Clock moved backwards");

    }

    if (timestamp === this.lastTimestamp) {

      this.sequence = (this.sequence + 1n) & this.sequenceMask;

      if (this.sequence === 0n) {

        timestamp = this.tilNextMillis(this.lastTimestamp);

      }

    } else {

      this.sequence = 0n;

    }

    this.lastTimestamp = timestamp;

    return (((timestamp - this.twepoch) << this.timestampLeftShift) | (this.datacenterId << this.datacenterIdShift) | (this.workerId << this.workerIdShift) | this.sequence);

  }

}

const snowflake = new Snowflake(1, 1);

console.log(snowflake.nextId().toString());

Ví dụ đầu ra:

159488555397410304

So sánh Snowflake vs UUID vs ULID

Tính năng

AUTO_INCREMENT

UUID v4

ULID

Snowflake

Duy nhất Toàn cầu

Không

Phân tán

Không

Có thể Sắp xếp

Không

Gọn nhẹ

Không

Trung bình

Hiệu suất Ghi cao

Trung bình

Thấp

Trung bình

Cao

Ứng dụng Thực tế

Nhiều nền tảng lớn sử dụng Snowflake hoặc các bộ tạo ID phân tán tương tự.

Công ty

Hệ thống

Twitter

Snowflake gốc

Discord

Snowflake ID

Instagram / Meta

ID phân tán dựa trên thời gian

TikTok

Bộ tạo ID phân tán nội bộ

Alibaba

Leaf ID Generator

Các cơ sở hạ tầng này phụ thuộc rất nhiều vào:

  • Khả năng mở rộng theo chiều ngang

  • Microservices phân tán

  • Quy trình sự kiện thông lượng cao

Khi nào Bạn nên sử dụng Snowflake ID?

Snowflake là một lựa chọn tốt nếu:

  • Backend của bạn là phân tán

  • Bạn vận hành nhiều dịch vụ hoặc node

  • Bạn cần ID có thể sắp xếp

  • Bạn muốn tránh các nút thắt cổ chai tập trung

  • Bạn yêu cầu tạo ID thông lượng cao

Snowflake có thể không lý tưởng nếu:

  • Bạn cần ID không thể đoán trước về mặt mật mã

  • Cơ sở hạ tầng của bạn có đồng hồ không đáng tin cậy

  • Hệ thống của bạn tương đối nhỏ

  • Bạn cần các mã định danh công khai mờ (opaque public identifiers)

Trong một số trường hợp, UUID vẫn là lựa chọn tốt hơn.

Các Thực hành Tốt nhất

Nên làm

  • Trả về Snowflake ID dưới dạng chuỗi trong API

  • Sử dụng bigint nội bộ khi cần

  • Đồng bộ hóa đồng hồ bằng NTP

  • Quản lý cẩn thận các ID worker và ID máy

  • Giám sát tràn chuỗi sequence (sequence overflow)

  • Triển khai bảo vệ chống chạy lùi đồng hồ (rollback protection for clocks)

Nên tránh

  • Xử lý Snowflake ID như số JavaScript thông thường

  • Vô tình tái sử dụng ID máy

  • Để lộ ID có thể dự đoán công khai khi việc liệt kê (enumeration) là quan trọng

  • Phụ thuộc vào đồng hồ không đồng bộ

Kết luận

Snowflake ID vẫn là một trong những ý tưởng tao nhã nhất trong kỹ thuật backend phân tán.

Chúng giải quyết một vấn đề khó một cách khó tin: tạo ra các ID độc nhất toàn cầu, có thể sắp xếp theo thời gian mà không cần dựa vào cơ sở hạ tầng tập trung.

Thiết kế của chúng cân bằng giữa:

  • Khả năng mở rộng

  • Hiệu suất

  • Thứ tự

  • Lưu trữ gọn nhẹ

  • Độc lập phân tán

Đây là lý do tại sao các bộ tạo ID kiểu Snowflake tiếp tục cung cấp sức mạnh cho một số nền tảng lớn nhất thế giới — từ các hệ thống truyền thông xã hội đến quy trình phân tích và kiến trúc microservice hiện đại.

Đối với các kỹ sư backend xây dựng hệ thống phân tán, Snowflake không còn chỉ là một chi tiết triển khai. Đó là một khái niệm nền tảng đáng được tìm hiểu sâu sắc.

Authors


hoangpm@strix

Hoang Pham Minh

Creative Full-Stack Developer at Vietstrix Team


Founder of Vietstrix Building digital products & systems

Tags:SEOVietstrixBlogsDự án websiteGoLangFullstack developmentBackendHệ Thống